package com.zhang.runner;

import cn.hutool.crypto.SecureUtil;
import com.zhang.constants.ApiConstant;
import com.zhang.modules.api.annotation.ApiPermission;
import com.zhang.modules.api.entity.Api;
import com.zhang.modules.api.service.IApiGroupService;
import com.zhang.modules.api.service.IApiService;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.security.Security;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
public class ApiDetectionRunner implements ApplicationRunner,Ordered {

    private static final String DEFAULT_GROUP_NAME = "默认分组";

    private IApiService apiService;

    private IApiGroupService groupService;


    private RequestMappingHandlerMapping handlerMapping;


    private AsyncTaskExecutor taskExecutor;

    private Map<String,String>  groupMap = new HashMap();


    public ApiDetectionRunner(IApiService apiService, RequestMappingHandlerMapping handlerMapping, AsyncTaskExecutor taskExecutor) {
        this.apiService = apiService;
        this.handlerMapping = handlerMapping;
        this.taskExecutor = taskExecutor;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = handlerMapping.getHandlerMethods();
        if (MapUtils.isEmpty(handlerMethodMap)) {
            return;
        }
        //任务执行器
        this.handleApi();
    }

    private void handleApi() {
        List<Api> apis = detectAppApi(handlerMapping);
        Map<String, List<Api>> groupingBy = apis
                .stream()
                .collect(
                        Collectors.groupingBy(
                                Api::getPid,
                                Collectors.toList()
                        )
                );

        List<String> groupNames = new ArrayList<>(groupingBy.keySet());
        groupNames.add(DEFAULT_GROUP_NAME);

        //创建接口分组，保存接口信息
        groupNames.forEach((name) -> {
            Api group = apiService.findByNameEquals(name);
            if(group == null){
                Api apiGroup = new Api();
                apiGroup.setAnonymous(false);
                apiGroup.setApiGroup(true);
                apiGroup.setStatus(ApiConstant.API_STATUS_ENABLE);
                apiGroup.setName(name);
                apiGroup.setPid("0");
                apiGroup.setCode(groupMap.get(name)==null?"DEFAULT":groupMap.get(name));
                apiGroup.setSort(0);
                apiService.save(apiGroup);
            }else{
                //更新组信息 更新权限编码信息
                group.setCode(groupMap.get(name)==null?"DEFAULT":groupMap.get(name));
                apiService.update(group);
            }

        });


        apis.forEach(api -> {
            Api group = apiService.findByNameEquals(api.getPid());
            Api created = apiService.findByPathEquals(api.getPath());


            if(created != null){
                //更新组id，权限编码，接口名称
                created.setPid(group.getId());
                created.setName(api.getName());
                created.setCode(api.getPermissionCode());
            }

            api.setPid(group.getId());


            if (created != null){
                apiService.update(created);
            }else{
                apiService.save(api);
            }
        });

    }

    /**
     * 获取应用Api接口
     * @param handlerMapping
     * @return
     */
    private List<Api> detectAppApi(RequestMappingHandlerMapping handlerMapping) {
        Map<RequestMappingInfo, HandlerMethod>  handlerMethodMap = handlerMapping.getHandlerMethods();
        if (MapUtils.isEmpty(handlerMethodMap)) {
            return new ArrayList<>();
        }
        List<Api> apis = new ArrayList<>();
        handlerMethodMap.forEach((requestMappingInfo, handlerMethod) -> {
            Api api = resolveApi(handlerMethod);
            if(api != null){
                apis.add(api);
            }
        });
        return apis;
    }

    /**
     * 解析Api
     * @param handlerMethod
     * @return
     */
    private Api resolveApi(HandlerMethod handlerMethod) {

        Class beanType = handlerMethod.getBeanType();
        io.swagger.annotations.Api apiInfo = AnnotationUtils.findAnnotation(beanType, io.swagger.annotations.Api.class);
        if(apiInfo == null) return null;



        Api api = new Api();

        ApiPermission permission  = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), ApiPermission.class);
        //api是否运行匿名访问
        api.setAnonymous(permission != null && permission.anonymous());
        api.setApiGroup(false);
        //暂时设置成组名称
        String[] tags = apiInfo != null ? apiInfo.tags() : null;
        if (tags != null && tags.length > 0) {
            api.setPid(tags[0]);
            //添加组权限信息到全局变量中
            if (!groupMap.containsKey(tags[0])){
                ApiPermission groupPermission = AnnotationUtils.findAnnotation(beanType, ApiPermission.class);
                groupMap.put(tags[0],groupPermission.value());
            }
        }else{
            api.setPid(DEFAULT_GROUP_NAME);
        }
        api.setStatus(ApiConstant.API_STATUS_ENABLE);

        //设置api的路径信息
        //用于获取 方法path 和 Controller path
        RequestMapping parentMapping = AnnotatedElementUtils.findMergedAnnotation(beanType, RequestMapping.class);
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(handlerMethod.getMethod(), RequestMapping.class);
        String prefixPath = path(parentMapping);
        PathMatcher pathMatcher = new AntPathMatcher("/");
        api.setPath(pathMatcher.combine(prefixPath, path(requestMapping)));


        //获取api接口的名称，ApiOperation注解的值，或者方法名
        ApiOperation operation = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), ApiOperation.class);
        api.setName(operation != null ? operation.value() : handlerMethod.getMethod().getName());
        api.setSort(0);

        //权限编码设置
        if (permission != null) {
            api.setCode(StringUtils.isNotEmpty(permission.code()) ? permission.code() : permission.value());
        }


        return api;
    }


    /**
     * 解析路径
     * @param mapping
     * @return
     */
    public static String path(RequestMapping mapping){
        String[] paths = mapping != null ? mapping.path() : null;
        return paths != null && paths.length > 0 ? paths[0] : "/";
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
